from Goldenberry.optimization.base.GbSolution import GbIndividual
from Goldenberry.statistics.distributions import Gaussian, GaussianTrunc

import random as ran
import numpy as np
import abc
class InitPopGenerator(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def generate_pop(self, params, solution_domain, cand_size, var_size, range_min, range_max):
        raise NotImplementedError()

class InitPopRandomGenerator(InitPopGenerator):
    """description of class"""
    def generate_pop(self, params, solution_domain, cand_size, var_size, range_min, range_max):
        population = []
        if solution_domain == 'Binary': 
            for x in range(cand_size):
                #a = np.random.random_integers(0, 1, var_size)
                population.append(GbIndividual(np.array(np.random.random_integers(0, 1, var_size))))   
        elif solution_domain == 'Real':
            for x in range(cand_size):
                #a = np.random.uniform(range_min, range_max, var_size)
                population.append(GbIndividual(np.array(np.random.uniform(range_min, range_max, var_size))))
        return population

class InitPopSeededGenerator(InitPopGenerator):
    """description of class"""
    def generate_pop(self, params, solution_domain, cand_size, var_size, range_min, range_max):
        population = params
        if solution_domain == 'Binary': 
            for x in range(len(params), cand_size):
                population.append(GbIndividual(np.array(np.random.random_integers(0, 1, var_size)))) 
        elif solution_domain == 'Real': 
            for x in range(len(params), cand_size):
                population.append(GbIndividual(np.array(np.random.uniform(range_min, range_max, var_size))))
        return population

class InitPopBiasedGenerator(InitPopGenerator):
    """description of class"""
    def generate_pop(self, params, solution_domain, cand_size, var_size, range_min, range_max):
        cont_indi = 0
        population = []
        # generate individuals in the bias
        for bias in params:
            dist = GaussianTrunc(means = np.tile(bias['mu'], 1), stdevs = bias['sigma'], low = bias['range_min'], high = bias['range_max'])
            #c = np.array([[-600.0,600.0,102.5,3.4,0]])
            for x in range(int(bias['perc'] * cand_size)):
                population.append(GbIndividual(dist.sample(10)[0].base))
                cont_indi += 1
        # generate the unbiased population
        for y in range(cont_indi, cand_size):
            population.append(GbIndividual(np.array(np.random.uniform(range_min, range_max, var_size))))
            """for x in range(len(self.seeds), self.cand_size):
                self.population.append(GbIndividual(np.array(np.random.uniform(self.range_min, self.range_max, self.var_size))))"""
        return population